/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.ppm.gtm.mas;

import bgu.ppm.gtm.agents.TurnBasedAgent;
import bgu.ppm.gtm.base.GameTheoryModel;
import bgu.ppm.gtm.base.ImmutableStrategy;
import bgu.ppm.gtm.base.PlayerValueFunction;
import bgu.ppm.gtm.base.StrategyProfile;
import bgu.ppm.sim.api.exec.TickBasedExecutable;
import bgu.ppm.sim.api.exec.TickBasedExecutionSystem;
import bgu.ppm.sim.api.mas.MultiAgentSystem;
import bgu.ppm.sim.api.mas.TerminationCondition;
import bgu.sonar.util.evt.EventListeners;
import java.util.List;

/**
 *
 * @author User
 */
public class IterativeBestResponceTerminationCondition implements TerminationCondition {

    private EventListeners<TerminationListener> listeners = EventListeners.create(TerminationListener.class);
    private int numberOfUnimprovedSteps;
    private MultiAgentSystem<GameTheoryModel> mas;
    private ImmutableStrategy lastChoosenStrategy;
    private int round;

    @Override
    public void initialize(MultiAgentSystem mas) {
        this.mas = mas;

        numberOfUnimprovedSteps = 0;
        
        round = 0;
    }

    @Override
    public boolean shouldTerminate() {
        return (numberOfUnimprovedSteps >= mas.getGlobalModel().getNumberOfAgents());
    }

    @Override
    public EventListeners<TerminationListener> getListeners() {
        return listeners;
    }

    @Override
    public void beforeTick(TickBasedExecutionSystem execs, TickBasedExecutable executable) {
        if (executable instanceof TurnBasedAgent) {
            lastChoosenStrategy = mas.getGlobalModel().getCurrentStrategyProfile().getSelectedStrategy(executable.getId());
            System.out.println("Last Known Strategy For Agent " + executable.getId() + " : " + lastChoosenStrategy);
        }
        
        System.out.println("Starting choice: " + round++);
    }

    @Override
    public void afterTick(TickBasedExecutionSystem execs, TickBasedExecutable executable) {
        if (executable instanceof TurnBasedAgent && lastChoosenStrategy != null) { //TODO: FIX IT!!
            PlayerValueFunction u = mas.getGlobalModel().getUtilityFunction();
            StrategyProfile sp = mas.getGlobalModel().getCurrentStrategyProfile();

            double ub = u.calculate(executable.getId(), lastChoosenStrategy, sp);
            double ua = u.calculate(executable.getId(), sp.getSelectedStrategy(executable.getId()), sp);
            
            System.out.println("ua: " + ua + ", ub: " + ub);

            if (ub > ua) {
                throw new RuntimeException("Agent: " + executable.getId() + " choose not legal action.");
            }

            if (ub == ua) {
                numberOfUnimprovedSteps++;
            }

            if (ub < ua) {
                numberOfUnimprovedSteps = 0;
            }

            if (shouldTerminate()) {
                listeners.fire().onTerminationNeeded(this);
//                throw new RuntimeException("Execution must stop");
            }
        }
    }

    @Override
    public void onExecutablesEnded(TickBasedExecutionSystem execs, List<TickBasedExecutable> executables) {
    }

    @Override
    public void beforeExecutableAdded(TickBasedExecutionSystem execs, TickBasedExecutable executable) {
    }

    @Override
    public void afterExecutableAdded(TickBasedExecutionSystem execs, TickBasedExecutable executable) {
    }

    @Override
    public void beforeExecutableRemoved(TickBasedExecutionSystem execs, TickBasedExecutable executable) {
    }

    @Override
    public void afterExecutableRemoved(TickBasedExecutionSystem execs, TickBasedExecutable executable) {
    }
}
